Analiza medijske pokrivenosti inflacije u Hrvatskoj

Eksploratorni pregled, konstrukcija indeksa i analiza prediktivnosti

Author

lux

Published

29. prosinca 2025.

1 Uvod

Ovaj izvještaj predstavlja sveobuhvatnu analizu medijske pokrivenosti inflacije u Hrvatskoj u razdoblju od siječnja 2021. do studenog 2024. godine. Analiza se temelji na člancima prikupljenim iz hrvatskih online medija koristeći naprednu metodologiju filtriranja i validacije sadržaja.

1.1 Motivacija i kontekst

Inflacija je tijekom 2022. i 2023. godine postala središnja tema ekonomske rasprave u Hrvatskoj i šire. Ovaj izvještaj nastoji odgovoriti na ključna pitanja:

  • Kako se medijsko izvještavanje o inflaciji razvijalo kroz vrijeme?
  • Je li medijska pozornost odgovarala stvarnim inflacijskim pritiscima?
  • Može li se medijska pozornost koristiti kao prediktor ili rani indikator inflacije?
  • Koje su teme i aspekti inflacije najzastupljeniji u medijima?

1.2 Struktura izvještaja

  1. Metodologija prikupljanja podataka detaljan opis procesa identifikacije relevantnih članaka
  2. Eksploratorni pregled struktura i karakteristike dataseta
  3. Vremenska analiza dinamika izvještavanja kroz različite vremenske horizonte
  4. Analiza sadržaja i text mining dubinska analiza sadržaja članaka
  5. Analiza semantičkih pojmova brojanje inflacijskih i srodnih pojmova
  6. GIMES Indeks konstrukcija robusnog indeksa medijske inflacije
  7. Dinamike različitih frekvencija M/m, 3M, 6M sezonski prilagođene stope
  8. Validacija sa službenim podacima usporedba s Eurostat HICP podacima
  9. Analiza prediktivnosti istraživanje lead/lag odnosa
  10. Zaključci i implikacije
Prikaži kod
dt <- as.data.table(read.xlsx(here("data", "inflacija_filtered.xlsx")))
if(is.numeric(dt$DATE)) {
  dt[, DATE := as.Date(DATE, origin = "1899-12-30")]
} else {
  dt[, DATE := as.Date(DATE)]
}

if("text_length" %in% names(dt)) {
  dt[, text_length := as.numeric(text_length)]
}
if("REACH" %in% names(dt)) {
  dt[, REACH := as.numeric(REACH)]
}
if("INTERACTIONS" %in% names(dt)) {
  dt[, INTERACTIONS := as.numeric(INTERACTIONS)]
}

# Dodaj AUTO_SENTIMENT ako ne postoji
if(!"AUTO_SENTIMENT" %in% names(dt)) {
  dt[, AUTO_SENTIMENT := fcase(
    stri_detect_regex(tolower(FULL_TEXT), 
                     "kriza|katastrofa|strah|panika|pogoršanj|problem|visok.{1,20}inflacij", 
                     case_insensitive = TRUE), -1,
    stri_detect_regex(tolower(FULL_TEXT), 
                     "pad inflacije|usporavanje|stabilizacij|poboljšanj|nizak.{1,20}inflacij", 
                     case_insensitive = TRUE), 1,
    default = 0
  )]
} else {
  dt[, AUTO_SENTIMENT := as.numeric(AUTO_SENTIMENT)]
}

dt[, `:=`(
  date = DATE,
  year = year(DATE),
  month = month(DATE),
  week = isoweek(DATE),
  yearmonth = floor_date(DATE, "month"),
  yearweek = floor_date(DATE, "week")
)]

dt <- dt[date <= as.Date("2024-11-01")]

2 Metodologija identifikacije članaka o inflaciji

2.1 Pregled procesa filtriranja

Identifikacija relevantnih članaka provedena je kroz šestostupanjski proces filtriranja koji kombinira strukturne kriterije, ključne riječi i kontekstualnu validaciju.

2.2 Pregled filtera

Filter 1: Tip izvora (samo web) Filter 2: Relevantni news portali (80+ verificiranih portala) Filter 3: Minimalna duljina teksta (>= 500 znakova) Filter 4: Naslov mora sadržavati inflacijske pojmove Filter 5: Core inflacijski pojmovi u tekstu Filter 6: Hrvatski kontekst (reference na hrvatsku ekonomiju)

Detaljni opis svakog filtera i regex uzoraka dostupan je u dokumentaciji projekta.

3 Eksploratorni pregled podataka

3.1 Osnovne statistike

Prikaži kod
stats_summary <- data.table(
  Metrika = c(
    "Ukupan broj članaka",
    "Vremenski raspon",
    "Broj dana",
    "Prosječno članaka dnevno",
    "Broj izvora (portala)",
    "Broj kategorija izvora",
    "Članci sa sentimentom"
  ),
  Vrijednost = c(
    format(nrow(dt), big.mark = ","),
    paste(format(min(dt$date), "%d.%m.%Y"), "do", format(max(dt$date), "%d.%m.%Y")),
    as.character(as.numeric(max(dt$date) - min(dt$date))),
    round(nrow(dt) / as.numeric(max(dt$date) - min(dt$date)), 1),
    length(unique(dt$FROM)),
    length(unique(dt$source_category)),
    format(sum(!is.na(dt$AUTO_SENTIMENT)), big.mark = ",")
  )
)

kable(stats_summary, col.names = c("Metrika", "Vrijednost"),
      caption = "Osnovne statistike dataseta") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Osnovne statistike dataseta
Metrika Vrijednost
Ukupan broj članaka 46,107
Vremenski raspon 01.01.2021 do 08.01.2024
Broj dana 1102
Prosječno članaka dnevno 41.8
Broj izvora (portala) 115
Broj kategorija izvora 5
Članci sa sentimentom 46,107

3.2 Distribucija po kategorijama izvora

Prikaži kod
cat_summary <- dt[, .(
  N = .N,
  Postotak = round(.N / nrow(dt) * 100, 1)
), by = source_category][order(-N)]

ggplot(cat_summary, aes(x = reorder(source_category, N), y = N, fill = source_category)) +
  geom_col(show.legend = FALSE) +
  geom_text(aes(label = paste0(format(N, big.mark = ","), "\n(", Postotak, "%)")), 
            hjust = -0.1, size = 3.5) +
  coord_flip() +
  scale_y_continuous(labels = comma, expand = expansion(mult = c(0, 0.2))) +
  scale_fill_manual(values = c("national" = colors_gimes["primary"],
                               "business" = colors_gimes["accent"],
                               "regional" = colors_gimes["success"],
                               "specialized" = colors_gimes["warning"],
                               "opinion" = colors_gimes["secondary"])) +
  labs(
    title = "Broj članaka po kategoriji izvora",
    x = NULL,
    y = "Broj članaka"
  ) +
  theme(
    plot.title = element_text(face = "bold"),
    panel.grid.major.y = element_blank()
  )

Distribucija članaka po kategorijama izvora

3.3 Top 20 izvora

Prikaži kod
top_sources <- dt[, .(N = .N), by = FROM][order(-N)][1:20]

ggplot(top_sources, aes(x = reorder(FROM, N), y = N)) +
  geom_col(fill = colors_gimes["primary"]) +
  geom_text(aes(label = format(N, big.mark = ",")), hjust = -0.1, size = 3) +
  coord_flip() +
  scale_y_continuous(labels = comma, expand = expansion(mult = c(0, 0.15))) +
  labs(
    title = "Top 20 izvora po broju članaka o inflaciji",
    x = NULL,
    y = "Broj članaka"
  ) +
  theme(
    plot.title = element_text(face = "bold"),
    panel.grid.major.y = element_blank()
  )

20 najaktivnijih izvora

3.4 Distribucija duljine teksta

Prikaži kod
if("text_length" %in% names(dt)) {
  ggplot(dt, aes(x = text_length)) +
    geom_histogram(bins = 50, fill = colors_gimes["primary"], alpha = 0.8, color = "white") +
    geom_vline(xintercept = median(dt$text_length, na.rm = TRUE), 
               color = colors_gimes["secondary"], linetype = "dashed", linewidth = 1) +
    annotate("text", x = median(dt$text_length, na.rm = TRUE) + 500, 
             y = Inf, vjust = 2, hjust = 0,
             label = paste("Medijan:", format(round(median(dt$text_length, na.rm = TRUE)), big.mark = ",")),
             color = colors_gimes["secondary"], fontface = "bold") +
    scale_x_continuous(labels = comma) +
    scale_y_continuous(labels = comma) +
    labs(
      title = "Distribucija duljine članaka",
      subtitle = "Broj znakova u FULL_TEXT polju",
      x = "Broj znakova",
      y = "Broj članaka"
    ) +
    theme(plot.title = element_text(face = "bold"))
}

Distribucija duljine članaka

4 Vremenska analiza

4.1 Dnevna frekvencija članaka o inflaciji

Prikaži kod
daily <- dt[, .(N = .N), by = date][order(date)]
daily[, MA7 := frollmean(N, n = 7, align = "center")]
daily[, MA30 := frollmean(N, n = 30, align = "center")]

ggplot(daily, aes(x = date)) +
  geom_col(aes(y = N), fill = colors_gimes["light"], alpha = 0.5, width = 1) +
  geom_line(aes(y = MA7, color = "7-dnevni prosjek"), linewidth = 0.8, na.rm = TRUE) +
  geom_line(aes(y = MA30, color = "30-dnevni prosjek"), linewidth = 1.2, na.rm = TRUE) +
  scale_x_date(date_breaks = "3 months", date_labels = "%b\n%Y") +
  scale_y_continuous(labels = comma) +
  scale_color_manual(values = c("7-dnevni prosjek" = colors_gimes["accent"],
                                "30-dnevni prosjek" = colors_gimes["secondary"])) +
  labs(
    title = "Dnevna frekvencija članaka o inflaciji",
    subtitle = "Broj članaka po danu sa kliznim prosjekom | Samostalni indikator medijske pozornosti",
    x = NULL,
    y = "Broj članaka",
    color = "Klizni prosjek"
  ) +
  theme(
    plot.title = element_text(face = "bold", size = 14),
    plot.subtitle = element_text(size = 10),
    legend.position = "bottom",
    axis.text.x = element_text(size = 9)
  )

Dnevni broj članaka o inflaciji

4.2 Mjesečna dinamika

Prikaži kod
monthly <- dt[, .(N = .N), by = yearmonth][order(yearmonth)]
monthly[, MA3 := frollmean(N, n = 3, align = "center")]

p_monthly <- ggplot(monthly, aes(x = yearmonth)) +
  geom_col(aes(y = N), fill = colors_gimes["primary"], alpha = 0.7, width = 25) +
  geom_line(aes(y = MA3), color = colors_gimes["secondary"], linewidth = 1.2, na.rm = TRUE) +
  geom_point(aes(y = MA3), color = colors_gimes["secondary"], size = 2, na.rm = TRUE) +
  scale_x_date(date_breaks = "3 months", date_labels = "%b\n%Y") +
  scale_y_continuous(labels = comma) +
  labs(
    title = "Mjesečni broj članaka o inflaciji",
    subtitle = "Crvena linija = 3-mjesečni klizni prosjek",
    x = NULL,
    y = "Broj članaka"
  ) +
  theme(
    plot.title = element_text(face = "bold"),
    axis.text.x = element_text(size = 8)
  )

p_monthly

Mjesečni broj članaka o inflaciji

4.3 Tjedna dinamika

Prikaži kod
weekly <- dt[, .(N = .N), by = yearweek][order(yearweek)]
weekly[, MA4 := frollmean(N, n = 4, align = "center")]

ggplot(weekly, aes(x = yearweek)) +
  geom_col(aes(y = N), fill = colors_gimes["primary"], alpha = 0.7, width = 5) +
  geom_line(aes(y = MA4), color = colors_gimes["secondary"], linewidth = 1.2, na.rm = TRUE) +
  geom_point(aes(y = MA4), color = colors_gimes["secondary"], size = 1.5, na.rm = TRUE) +
  scale_x_date(date_breaks = "3 months", date_labels = "%b\n%Y") +
  scale_y_continuous(labels = comma) +
  labs(
    title = "Tjedni broj članaka o inflaciji",
    subtitle = "Crvena linija = 4-tjedni klizni prosjek",
    x = NULL,
    y = "Broj članaka"
  ) +
  theme(
    plot.title = element_text(face = "bold"),
    axis.text.x = element_text(angle = 45, hjust = 1)
  )

Tjedni broj članaka o inflaciji

4.4 Godišnja usporedba

Prikaži kod
yearly_monthly <- dt[, .(N = .N), by = .(year, month)][order(year, month)]

ggplot(yearly_monthly, aes(x = month, y = N, color = factor(year), group = year)) +
  geom_line(linewidth = 1.2) +
  geom_point(size = 2.5) +
  scale_x_continuous(breaks = 1:12, labels = c("Sij", "Velj", "Ožu", "Tra", "Svi", "Lip",
                                                "Srp", "Kol", "Ruj", "Lis", "Stu", "Pro")) +
  scale_y_continuous(labels = comma) +
  scale_color_manual(values = c("2021" = "#3498DB", "2022" = "#E74C3C", 
                                "2023" = "#27AE60", "2024" = "#9B59B6")) +
  labs(
    title = "Mjesečna dinamika po godinama",
    x = "Mjesec",
    y = "Broj članaka",
    color = "Godina"
  ) +
  theme(
    plot.title = element_text(face = "bold"),
    legend.position = "bottom"
  )

Usporedba mjesečne dinamike po godinama

4.5 Distribucija po danima u tjednu

Prikaži kod
dt[, weekday_num := wday(date, week_start = 1)]
weekday_labels <- c("Ponedjeljak", "Utorak", "Srijeda", "Četvrtak", "Petak", "Subota", "Nedjelja")
dt[, weekday := factor(weekday_num, levels = 1:7, labels = weekday_labels)]

weekday_summary <- dt[, .(N = .N), by = weekday][order(weekday)]

ggplot(weekday_summary, aes(x = weekday, y = N)) +
  geom_col(fill = "gray40", show.legend = FALSE) +
  geom_text(aes(label = format(N, big.mark = ",")), vjust = -0.5, size = 3.5) +
  scale_y_continuous(labels = comma, expand = expansion(mult = c(0, 0.1))) +
  labs(
    title = "Broj članaka po danu u tjednu",
    x = NULL,
    y = "Broj članaka"
  ) +
  theme(
    plot.title = element_text(face = "bold"),
    axis.text.x = element_text(angle = 45, hjust = 1)
  )

Distribucija članaka po danima u tjednu

4.6 Sentiment kroz vrijeme

Prikaži kod
if("AUTO_SENTIMENT" %in% names(dt)) {
  sentiment_monthly <- dt[!is.na(AUTO_SENTIMENT), .(
    avg_sentiment = mean(AUTO_SENTIMENT),
    N = .N,
    pct_negative = sum(AUTO_SENTIMENT == -1) / .N * 100,
    pct_positive = sum(AUTO_SENTIMENT == 1) / .N * 100
  ), by = yearmonth][order(yearmonth)]
  
  ggplot(sentiment_monthly, aes(x = yearmonth)) +
    geom_hline(yintercept = 0, color = "gray50", linetype = "dashed") +
    geom_line(aes(y = avg_sentiment), color = colors_gimes["primary"], linewidth = 1) +
    geom_point(aes(y = avg_sentiment, size = N), color = colors_gimes["primary"], alpha = 0.6) +
    geom_smooth(aes(y = avg_sentiment), method = "loess", se = TRUE, 
                color = colors_gimes["secondary"], fill = colors_gimes["secondary"], alpha = 0.2) +
    scale_x_date(date_breaks = "3 months", date_labels = "%b\n%Y") +
    scale_size_continuous(range = c(2, 6), labels = comma) +
    labs(
      title = "Prosječni sentiment članaka kroz vrijeme",
      subtitle = "Crvena linija = LOESS trend",
      x = NULL,
      y = "Prosječni sentiment (-1 do 1)",
      size = "Broj članaka"
    ) +
    theme(
      plot.title = element_text(face = "bold"),
      legend.position = "bottom"
    )
}

Dinamika sentimenta kroz vrijeme

5 Dnevni broj spominjanja inflacije kao samostalni indikator

Dnevni broj članaka o inflaciji predstavlja jednostavan ali informativan pokazatelj medijske pozornosti na inflacijske teme. Ovaj indikator može služiti kao real-time proxy za javnu percepciju inflacijskih pritisaka u Hrvatskoj.

5.1 Metodologija

Indikator se temelji na jednostavnom brojanju članaka koji zadovoljavaju kriterije filtriranja za inflacijsku tematiku. Za izglađivanje dnevnih fluktuacija koristi se 30-dnevni klizni prosjek koji daje stabilniju sliku trenda medijske pozornosti.

5.2 Dnevni indikator medijske pozornosti na inflaciju

Prikaži kod
# Izračunaj statistike za anotacije
peak_date <- daily[which.max(MA30), date]
peak_value <- daily[which.max(MA30), MA30]
avg_value <- mean(daily$MA30, na.rm = TRUE)

# Identificiraj ključne periode
daily[, period := fcase(
  date < as.Date("2022-01-01"), "Pred-inflacijski period",
  date >= as.Date("2022-01-01") & date < as.Date("2023-07-01"), "Inflacijski vrhunac",
  date >= as.Date("2023-07-01"), "Normalizacija"
)]

ggplot(daily, aes(x = date)) +
  # Pozadinske zone za periode
  geom_rect(aes(xmin = as.Date("2022-01-01"), xmax = as.Date("2023-07-01"),
                ymin = -Inf, ymax = Inf), fill = colors_gimes["secondary"], alpha = 0.1) +
  # Dnevni podaci kao stupci
  geom_col(aes(y = N), fill = "gray80", alpha = 0.4, width = 1) +
  # Klizni prosjeci
  geom_line(aes(y = MA7), color = colors_gimes["accent"], linewidth = 0.6, alpha = 0.6, na.rm = TRUE) +
  geom_line(aes(y = MA30), color = colors_gimes["primary"], linewidth = 1.3, na.rm = TRUE) +
  # Horizontalna linija za prosjek
  geom_hline(yintercept = avg_value, color = colors_gimes["warning"], linetype = "dashed", linewidth = 0.8) +
  # Anotacija za vrhunac
  annotate("point", x = peak_date, y = peak_value, color = colors_gimes["secondary"], size = 4) +
  annotate("text", x = peak_date, y = peak_value + 3, 
           label = paste0("Vrhunac: ", format(peak_date, "%d.%m.%Y")),
           color = colors_gimes["secondary"], fontface = "bold", size = 3.5, hjust = 0) +
  # Anotacija za prosjek
  annotate("text", x = min(daily$date) + 30, y = avg_value + 2,
           label = paste0("Prosjek: ", round(avg_value, 1), " članaka/dan"),
           color = colors_gimes["warning"], fontface = "bold", size = 3.5, hjust = 0) +
  # Anotacije za periode
  annotate("text", x = as.Date("2022-10-01"), y = max(daily$N, na.rm = TRUE) * 0.95,
           label = "Inflacijski vrhunac", color = colors_gimes["secondary"], 
           fontface = "italic", size = 3.5) +
  scale_x_date(date_breaks = "3 months", date_labels = "%b\n%Y") +
  scale_y_continuous(labels = comma, expand = expansion(mult = c(0, 0.05))) +
  labs(
    title = "Dnevni broj spominjanja inflacije u hrvatskim medijima",
    subtitle = "Samostalni indikator medijske pozornosti | Tamna linija = 30-dnevni MA | Svijetla linija = 7-dnevni MA",
    x = NULL,
    y = "Broj članaka"
  ) +
  theme(
    plot.title = element_text(face = "bold", size = 14),
    plot.subtitle = element_text(size = 10, color = "gray40"),
    panel.grid.minor = element_blank(),
    axis.text.x = element_text(size = 9)
  )

Dnevni broj spominjanja inflacije kao samostalni indikator

5.3 Normalizirani dnevni indikator (0-100)

Prikaži kod
# Normaliziraj 30-dnevni MA na skalu 0-100
daily[, MA30_norm := (MA30 - min(MA30, na.rm = TRUE)) / 
        (max(MA30, na.rm = TRUE) - min(MA30, na.rm = TRUE)) * 100]

ggplot(daily[!is.na(MA30_norm)], aes(x = date)) +
  geom_ribbon(aes(ymin = 0, ymax = MA30_norm), fill = colors_gimes["accent"], alpha = 0.3) +
  geom_line(aes(y = MA30_norm), color = colors_gimes["primary"], linewidth = 1.2) +
  # Zone intenziteta
  geom_hline(yintercept = c(25, 50, 75), linetype = "dotted", color = "gray60") +
  annotate("text", x = max(daily$date) - 60, y = 12.5, label = "Niska pozornost", 
           color = "gray50", size = 3, fontface = "italic") +
  annotate("text", x = max(daily$date) - 60, y = 37.5, label = "Umjerena pozornost", 
           color = "gray50", size = 3, fontface = "italic") +
  annotate("text", x = max(daily$date) - 60, y = 62.5, label = "Visoka pozornost", 
           color = "gray50", size = 3, fontface = "italic") +
  annotate("text", x = max(daily$date) - 60, y = 87.5, label = "Vrlo visoka pozornost", 
           color = "gray50", size = 3, fontface = "italic") +
  scale_x_date(date_breaks = "3 months", date_labels = "%b\n%Y") +
  scale_y_continuous(limits = c(0, 100), breaks = seq(0, 100, 25)) +
  labs(
    title = "Normalizirani indikator medijske pozornosti na inflaciju",
    subtitle = "Skala 0-100 temeljena na 30-dnevnom kliznom prosjeku broja članaka",
    x = NULL,
    y = "Indeks medijske pozornosti"
  ) +
  theme(
    plot.title = element_text(face = "bold", size = 14),
    plot.subtitle = element_text(size = 10, color = "gray40"),
    panel.grid.minor = element_blank()
  )

Normalizirani dnevni indikator medijske inflacije

5.4 Statistike dnevnog indikatora

Prikaži kod
daily_stats <- data.table(
  Metrika = c(
    "Prosječan broj članaka dnevno",
    "Medijan članaka dnevno",
    "Maksimalan broj članaka (jedan dan)",
    "Datum maksimuma",
    "Standardna devijacija",
    "Prosječni 30-dnevni MA",
    "Maksimalni 30-dnevni MA",
    "Datum vrhunca (30-dnevni MA)"
  ),
  Vrijednost = c(
    round(mean(daily$N), 1),
    round(median(daily$N), 1),
    max(daily$N),
    format(daily[which.max(N), date], "%d.%m.%Y"),
    round(sd(daily$N), 1),
    round(mean(daily$MA30, na.rm = TRUE), 1),
    round(max(daily$MA30, na.rm = TRUE), 1),
    format(daily[which.max(MA30), date], "%d.%m.%Y")
  )
)

kable(daily_stats, caption = "Statistike dnevnog indikatora medijske pozornosti") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Statistike dnevnog indikatora medijske pozornosti
Metrika Vrijednost
Prosječan broj članaka dnevno 43.5
Medijan članaka dnevno 30
Maksimalan broj članaka (jedan dan) 256
Datum maksimuma 05.01.2023
Standardna devijacija 42.2
Prosječni 30-dnevni MA 44.1
Maksimalni 30-dnevni MA 106.1
Datum vrhunca (30-dnevni MA) 16.01.2023

6 Analiza semantičkih pojmova povezanih s inflacijom

Ova sekcija proširuje analizu brojanja riječi inflacija na širi skup semantički povezanih pojmova koji mogu bolje pratiti inflacijske trendove u medijskom izvještavanju.

6.1 Definicija rječnika inflacijskih pojmova

Prikaži kod
# Definicija rječnika inflacijskih i semantički povezanih pojmova
# Pojmovi su grupirani po kategorijama za lakšu interpretaciju

semantic_terms <- list(
  
  # Direktni inflacijski pojmovi
  inflacija_direktno = c(
    "inflacij[a-zčćžšđ]*",           # inflacija, inflacijski, inflacijom...
    "dezinflacij[a-zčćžšđ]*",        # dezinflacija
    "hiperinflacij[a-zčćžšđ]*",      # hiperinflacija
    "stagflacij[a-zčćžšđ]*"          # stagflacija
  ),
  
  # Cijene i poskupljenja
  cijene_poskupljenja = c(
    "poskupljenj[a-zčćžšđ]*",        # poskupljenje
    "poskupi[a-zčćžšđ]*",            # poskupiti, poskupilo
    "porast.{0,10}cijen[a-zčćžšđ]*", # porast cijena
    "rast.{0,10}cijen[a-zčćžšđ]*",   # rast cijena
    "viš[aei].{0,10}cijen[a-zčćžšđ]*", # više cijene
    "skok.{0,10}cijen[a-zčćžšđ]*",   # skok cijena
    "skupoc[a-zčćžšđ]*",             # skupoća
    "skuplj[a-zčćžšđ]*"              # skuplje
  ),
  
  # Troškovi života
  troskovi_zivota = c(
    "troškov[a-zčćžšđ]*.{0,10}život[a-zčćžšđ]*",  # troškovi života
    "životn[a-zčćžšđ]*.{0,10}standard[a-zčćžšđ]*", # životni standard
    "kupovn[a-zčćžšđ]*.{0,10}moć[a-zčćžšđ]*",     # kupovna moć
    "egzistencij[a-zčćžšđ]*"         # egzistencija
  ),
  
  # Energija i gorivo
  energija_gorivo = c(
    "cijen[a-zčćžšđ]*.{0,10}energij[a-zčćžšđ]*",  # cijena energije
    "cijen[a-zčćžšđ]*.{0,10}goriva",              # cijena goriva
    "cijen[a-zčćžšđ]*.{0,10}struj[a-zčćžšđ]*",   # cijena struje
    "cijen[a-zčćžšđ]*.{0,10}plin[a-zčćžšđ]*",    # cijena plina
    "energetsk[a-zčćžšđ]*.{0,10}kriz[a-zčćžšđ]*" # energetska kriza
  ),
  
  # Hrana i prehrambeni proizvodi
  hrana = c(
    "cijen[a-zčćžšđ]*.{0,10}hran[a-zčćžšđ]*",    # cijena hrane
    "cijen[a-zčćžšđ]*.{0,10}namirnic[a-zčćžšđ]*", # cijena namirnica
    "prehrambeni[a-zčćžšđ]*.{0,10}proizvod[a-zčćžšđ]*", # prehrambeni proizvodi
    "cijen[a-zčćžšđ]*.{0,10}kruh[a-zčćžšđ]*",    # cijena kruha
    "cijen[a-zčćžšđ]*.{0,10}mlijeka"              # cijena mlijeka
  ),
  
  # Monetarna politika
  monetarna_politika = c(
    "kamatn[a-zčćžšđ]*.{0,10}stop[a-zčćžšđ]*",   # kamatna stopa
    "kamat[a-zčćžšđ]*",               # kamate
    "hnb",                             # HNB
    "ecb",                             # ECB
    "monetarn[a-zčćžšđ]*.{0,10}politik[a-zčćžšđ]*", # monetarna politika
    "euroz[a-zčćžšđ]*"                # eurozona
  ),
  
  # Plaće i primanja
  place_primanja = c(
    "plać[a-zčćžšđ]*",                # plaće
    "primanj[a-zčćžšđ]*",             # primanja
    "mirovn[a-zčćžšđ]*",              # mirovine
    "realna.{0,10}plać[a-zčćžšđ]*",  # realna plaća
    "rast.{0,10}plać[a-zčćžšđ]*"     # rast plaća
  ),
  
  # Indeksi i mjere
  indeksi_mjere = c(
    "hicp",                            # HICP
    "indeks.{0,10}potroš[a-zčćžšđ]*", # indeks potrošačkih cijena
    "cpi",                             # CPI
    "bazn[a-zčćžšđ]*.{0,10}inflacij[a-zčćžšđ]*", # bazna inflacija
    "jezgren[a-zčćžšđ]*.{0,10}inflacij[a-zčćžšđ]*" # jezgrena inflacija
  )
)

# Ispis definiranog rječnika
term_summary <- data.table(
  Kategorija = names(semantic_terms),
  Broj_pojmova = sapply(semantic_terms, length),
  Primjeri = sapply(semantic_terms, function(x) paste(head(x, 2), collapse = ", "))
)

kable(term_summary, 
      col.names = c("Kategorija", "Broj pojmova", "Primjeri regex uzoraka"),
      caption = "Pregled rječnika semantičkih pojmova") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Pregled rječnika semantičkih pojmova
Kategorija Broj pojmova Primjeri regex uzoraka
inflacija_direktno 4 inflacij[a-zčćžšđ]*, dezinflacij[a-zčćžšđ]*
cijene_poskupljenja 8 poskupljenj[a-zčćžšđ]*, poskupi[a-zčćžšđ]*
troskovi_zivota 4 troškov[a-zčćžšđ]*.{0,10}život[a-zčćžšđ]*, životn[a-zčćžšđ]*.{0,10}standard[a-zčćžšđ]*
energija_gorivo 5 cijen[a-zčćžšđ]*.{0,10}energij[a-zčćžšđ]*, cijen[a-zčćžšđ]*.{0,10}goriva
hrana 5 cijen[a-zčćžšđ]*.{0,10}hran[a-zčćžšđ]*, cijen[a-zčćžšđ]*.{0,10}namirnic[a-zčćžšđ]*
monetarna_politika 6 kamatn[a-zčćžšđ]*.{0,10}stop[a-zčćžšđ]*, kamat[a-zčćžšđ]*
place_primanja 5 plać[a-zčćžšđ]*, primanj[a-zčćžšđ]*
indeksi_mjere 5 hicp, indeks.{0,10}potroš[a-zčćžšđ]*

6.2 Brojanje semantičkih pojmova po člancima

Prikaži kod
# Funkcija za brojanje pojmova
count_terms <- function(text, patterns) {
  if(is.na(text) || text == "") return(0)
  text_lower <- tolower(text)
  sum(sapply(patterns, function(p) {
    stri_count_regex(text_lower, p)
  }))
}

# Izbroji svaku kategoriju pojmova za svaki članak
for(cat_name in names(semantic_terms)) {
  col_name <- paste0("count_", cat_name)
  dt[, (col_name) := sapply(FULL_TEXT, count_terms, patterns = semantic_terms[[cat_name]])]
}

# Ukupni broj svih semantičkih pojmova
dt[, count_all_semantic := rowSums(.SD), .SDcols = patterns(
  "^count_"
)]

# Broj samo direktnih inflacijskih pojmova (za usporedbu)
dt[, inflacija_count := sapply(FULL_TEXT, count_terms, 
                                patterns = semantic_terms$inflacija_direktno)]

6.3 Mjesečna agregacija semantičkih pojmova

Prikaži kod
# Agregiraj po mjesecu za svaku kategoriju
semantic_cols <- names(dt)[grepl("^count_", names(dt))]

monthly_semantic <- dt[, c(
  .(N = .N),
  lapply(.SD, sum, na.rm = TRUE),
  lapply(.SD, mean, na.rm = TRUE) |> setNames(paste0(names(.SD), "_avg"))
), by = yearmonth, .SDcols = semantic_cols][order(yearmonth)]

# Dodaj i ukupan broj članaka o inflaciji
monthly_semantic[, total_mentions := count_all_semantic]

6.4 Vizualizacija semantičkih kategorija kroz vrijeme

Prikaži kod
# Pripremi podatke za vizualizaciju
semantic_long <- melt(
  monthly_semantic[, .(yearmonth, 
                       count_inflacija_direktno,
                       count_cijene_poskupljenja,
                       count_troskovi_zivota,
                       count_energija_gorivo,
                       count_hrana,
                       count_monetarna_politika,
                       count_place_primanja,
                       count_indeksi_mjere)],
  id.vars = "yearmonth",
  variable.name = "kategorija",
  value.name = "broj"
)

# Mapiranje naziva kategorija
category_labels <- c(
  "count_inflacija_direktno" = "Inflacija (direktno)",
  "count_cijene_poskupljenja" = "Cijene/Poskupljenja",
  "count_troskovi_zivota" = "Troškovi života",
  "count_energija_gorivo" = "Energija/Gorivo",
  "count_hrana" = "Hrana",
  "count_monetarna_politika" = "Monetarna politika",
  "count_place_primanja" = "Plaće/Primanja",
  "count_indeksi_mjere" = "Indeksi/Mjere"
)

semantic_long[, kategorija_label := category_labels[as.character(kategorija)]]

ggplot(semantic_long, aes(x = yearmonth, y = broj, color = kategorija_label)) +
  geom_line(linewidth = 1) +
  facet_wrap(~kategorija_label, ncol = 2, scales = "free_y") +
  scale_x_date(date_breaks = "6 months", date_labels = "%b %y") +
  scale_color_brewer(palette = "Set2") +
  labs(
    title = "Dinamika semantičkih kategorija kroz vrijeme",
    subtitle = "Mjesečni broj spominjanja po kategoriji pojmova",
    x = NULL,
    y = "Broj spominjanja",
    color = NULL
  ) +
  theme(
    plot.title = element_text(face = "bold"),
    legend.position = "none",
    axis.text.x = element_text(angle = 45, hjust = 1),
    strip.text = element_text(face = "bold")
  )

Dinamika semantičkih kategorija kroz vrijeme

6.5 Usporedba kategorija s Eurostat HICP

Prikaži kod
# Dohvati HICP podatke (kopija iz originalne skripte)
eurostat_headline <- NULL
tryCatch({
  hicp_data <- get_eurostat("prc_hicp_manr", 
                            filters = list(geo = "HR", 
                                          coicop = "CP00",
                                          unit = "RCH_A"),
                            time_format = "date")
  setDT(hicp_data)
  eurostat_headline <- hicp_data[time >= "2021-01-01" & time <= "2024-11-01", 
                                   .(yearmonth = time, eurostat_hicp = values)]
}, error = function(e) {
  eurostat_headline <<- data.table(
    yearmonth = seq(as.Date("2021-01-01"), as.Date("2024-11-01"), by = "month"),
    eurostat_hicp = c(
      0.2, 0.6, 0.8, 1.9, 2.4, 2.3, 2.6, 3.0, 3.3, 3.8, 4.8, 5.5,
      5.8, 6.3, 7.3, 9.4, 10.8, 12.1, 12.3, 12.4, 12.8, 13.0, 13.0, 12.7,
      12.0, 11.1, 10.5, 9.2, 8.4, 8.2, 7.3, 7.7, 7.1, 5.3, 4.9, 4.7,
      4.3, 4.0, 3.9, 3.7, 3.6, 3.4, 3.2, 2.9, 2.8, 2.6, 2.4
    )
  )
})

# Spoji sa semantičkim podacima
semantic_hicp <- merge(monthly_semantic, eurostat_headline, by = "yearmonth", all.x = TRUE)

# Izračunaj korelacije za svaku kategoriju
correlation_results <- data.table(
  Kategorija = character(),
  Korelacija = numeric(),
  P_vrijednost = numeric()
)

for(col in semantic_cols[semantic_cols != "count_all_semantic"]) {
  cor_test <- cor.test(semantic_hicp[[col]], semantic_hicp$eurostat_hicp, 
                       use = "complete.obs")
  correlation_results <- rbind(correlation_results, data.table(
    Kategorija = gsub("count_", "", col),
    Korelacija = round(cor_test$estimate, 3),
    P_vrijednost = round(cor_test$p.value, 4)
  ))
}

# Dodaj i ukupni semantički indeks
cor_test_all <- cor.test(semantic_hicp$count_all_semantic, semantic_hicp$eurostat_hicp, 
                         use = "complete.obs")
correlation_results <- rbind(correlation_results, data.table(
  Kategorija = "SVE KATEGORIJE",
  Korelacija = round(cor_test_all$estimate, 3),
  P_vrijednost = round(cor_test_all$p.value, 4)
))

# Sortiraj po korelaciji
correlation_results <- correlation_results[order(-Korelacija)]

kable(correlation_results, 
      col.names = c("Kategorija pojmova", "Korelacija s HICP", "P vrijednost"),
      caption = "Korelacije semantičkih kategorija s Eurostat HICP inflacijom") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
  row_spec(which.max(correlation_results$Korelacija), bold = TRUE, 
           background = colors_gimes["success"])
Korelacije semantičkih kategorija s Eurostat HICP inflacijom
Kategorija pojmova Korelacija s HICP P vrijednost
inflacija_direktno 0.868 0.0000
place_primanja 0.776 0.0000
monetarna_politika 0.742 0.0000
SVE KATEGORIJE 0.661 0.0000
troskovi_zivota 0.591 0.0001
hrana 0.579 0.0002
energija_gorivo 0.493 0.0019
cijene_poskupljenja 0.465 0.0037
indeksi_mjere 0.407 0.0125

Korelacije semantičkih kategorija s HICP inflacijom

6.6 Semantički indeks vs službena inflacija

Prikaži kod
# Normaliziraj semantički indeks na skalu usporedivu s inflacijom
semantic_hicp[, semantic_norm := (count_all_semantic - min(count_all_semantic, na.rm = TRUE)) / 
                (max(count_all_semantic, na.rm = TRUE) - min(count_all_semantic, na.rm = TRUE)) * 
                max(eurostat_hicp, na.rm = TRUE)]

ggplot(semantic_hicp, aes(x = yearmonth)) +
  geom_col(aes(y = count_all_semantic / max(count_all_semantic, na.rm = TRUE) * 
                 max(eurostat_hicp, na.rm = TRUE)), 
           fill = colors_gimes["accent"], alpha = 0.4, width = 25) +
  geom_line(aes(y = eurostat_hicp, color = "Eurostat HICP"), linewidth = 1.5) +
  geom_point(aes(y = eurostat_hicp), color = colors_gimes["secondary"], size = 2) +
  scale_y_continuous(
    name = "HICP Inflacija (YoY %)",
    sec.axis = sec_axis(~. / max(semantic_hicp$eurostat_hicp, na.rm = TRUE) * 
                          max(semantic_hicp$count_all_semantic, na.rm = TRUE),
                        name = "Ukupno semantičkih pojmova")
  ) +
  scale_x_date(date_breaks = "3 months", date_labels = "%b\n%Y") +
  scale_color_manual(values = c("Eurostat HICP" = colors_gimes["secondary"])) +
  labs(
    title = "Ukupni broj semantičkih pojmova vs Eurostat HICP",
    subtitle = paste0("Korelacija: r = ", round(cor_test_all$estimate, 3)),
    x = NULL,
    color = NULL
  ) +
  theme(
    plot.title = element_text(face = "bold", size = 14),
    plot.subtitle = element_text(size = 11),
    legend.position = "bottom",
    axis.title.y.right = element_text(color = colors_gimes["accent"]),
    axis.text.y.right = element_text(color = colors_gimes["accent"]),
    axis.title.y.left = element_text(color = colors_gimes["secondary"])
  )

Ukupni semantički indeks vs Eurostat HICP

6.7 Najbolja kombinacija semantičkih pojmova

Prikaži kod
# Testiraj različite kombinacije kategorija
# Izračunaj kompozitni indeks koristeći samo top kategorije po korelaciji
top_categories <- correlation_results[Kategorija != "SVE KATEGORIJE"][order(-Korelacija)][1:4, Kategorija]

semantic_hicp[, top_composite := rowSums(.SD), 
              .SDcols = paste0("count_", top_categories)]

# Korelacija kompozitnog indeksa
cor_composite <- cor(semantic_hicp$top_composite, semantic_hicp$eurostat_hicp, 
                     use = "complete.obs")

# Normaliziraj za vizualizaciju
coef_composite <- max(semantic_hicp$eurostat_hicp, na.rm = TRUE) / 
                  max(semantic_hicp$top_composite, na.rm = TRUE)

ggplot(semantic_hicp, aes(x = yearmonth)) +
  geom_line(aes(y = top_composite * coef_composite, color = "Kompozitni indeks"), 
            linewidth = 1.2) +
  geom_line(aes(y = eurostat_hicp, color = "Eurostat HICP"), 
            linewidth = 1.2, linetype = "dashed") +
  scale_y_continuous(
    name = "HICP (%)",
    sec.axis = sec_axis(~./coef_composite, name = "Broj pojmova (kompozit)")
  ) +
  scale_x_date(date_breaks = "3 months", date_labels = "%b\n%Y") +
  scale_color_manual(values = c("Kompozitni indeks" = colors_gimes["accent"],
                                "Eurostat HICP" = colors_gimes["secondary"])) +
  labs(
    title = "Kompozitni semantički indeks (top 4 kategorije) vs HICP",
    subtitle = paste0("Kategorije: ", paste(top_categories, collapse = ", "), 
                     " | r = ", round(cor_composite, 3)),
    x = NULL,
    color = NULL
  ) +
  theme(
    plot.title = element_text(face = "bold"),
    legend.position = "bottom"
  )

Najbolja kombinacija semantičkih pojmova za predikciju inflacije

7 GIMES Indeks medijske inflacije

7.1 Metodologija

GIMES indeks (Government-Industry-Media Economic Sentiment) medijske inflacije konstruiran je kao kompozitni pokazatelj koji kombinira četiri dimenzije medijskog izvještavanja:

7.1.1 Komponente indeksa

  1. Volumen (40% težina)
    • Broj članaka o inflaciji u mjesecu
    • Normaliziran na skalu 0-100
    • Veći broj članaka = veća medijska pozornost
  2. Intenzitet (20% težina)
    • Prosječna duljina članaka (broj znakova)
    • Odražava dubinu analize
    • Duži članci = detaljnije izvještavanje
  3. Sentiment (20% težina)
    • Prosječni sentiment članaka (invertiran)
    • -1 (negativan), 0 (neutralan), 1 (pozitivan)
    • Negativniji sentiment = veća zabrinutost = viši indeks
  4. Doseg (20% težina)
    • Prosječni reach/interakcije ako dostupno
    • Inače zamijenjeno prosječnom vrijednosti (50)

7.1.2 Formula

\[GIMES = 0.4 \times V_{norm} + 0.2 \times I_{norm} + 0.2 \times (100 - S_{norm}) + 0.2 \times R_{norm}\]

gdje su: - \(V_{norm}\) = normalizirani volumen - \(I_{norm}\) = normalizirani intenzitet - \(S_{norm}\) = normalizirani sentiment (invertiran) - \(R_{norm}\) = normalizirani doseg

Indeks je skaliran na raspon 0-100, gdje viša vrijednost indicira veću medijsku pozornost i zabrinutost oko inflacije.

Prikaži kod
index_data <- dt[, .(
  volume = .N,
  avg_length = mean(text_length, na.rm = TRUE),
  avg_sentiment = mean(AUTO_SENTIMENT, na.rm = TRUE),
  avg_reach = if("REACH" %in% names(.SD)) mean(REACH, na.rm = TRUE) else NA_real_,
  total_reach = if("REACH" %in% names(.SD)) sum(REACH, na.rm = TRUE) else NA_real_,
  avg_interactions = if("INTERACTIONS" %in% names(.SD)) mean(INTERACTIONS, na.rm = TRUE) else NA_real_,
  # Dodaj semantičke komponente
  semantic_total = sum(count_all_semantic, na.rm = TRUE),
  semantic_inflacija = sum(count_inflacija_direktno, na.rm = TRUE),
  semantic_cijene = sum(count_cijene_poskupljenja, na.rm = TRUE),
  semantic_troskovi = sum(count_troskovi_zivota, na.rm = TRUE),
  semantic_energija = sum(count_energija_gorivo, na.rm = TRUE),
  semantic_hrana = sum(count_hrana, na.rm = TRUE),
  semantic_monetarna = sum(count_monetarna_politika, na.rm = TRUE),
  semantic_place = sum(count_place_primanja, na.rm = TRUE),
  semantic_indeksi = sum(count_indeksi_mjere, na.rm = TRUE)
), by = yearmonth][order(yearmonth)]

normalize <- function(x) {
  if(all(is.na(x))) return(rep(50, length(x)))
  min_x <- min(x, na.rm = TRUE)
  max_x <- max(x, na.rm = TRUE)
  if(max_x == min_x) return(rep(50, length(x)))
  (x - min_x) / (max_x - min_x) * 100
}

index_data[, `:=`(
  volume_norm = normalize(volume),
  length_norm = normalize(avg_length),
  sentiment_norm = normalize(avg_sentiment),
  reach_norm = normalize(avg_reach),
  semantic_norm = normalize(semantic_total)
)]

index_data[, gimes_index := 
  0.40 * volume_norm + 
  0.20 * length_norm + 
  0.20 * (100 - sentiment_norm) +
  0.20 * fifelse(is.na(reach_norm), 50, reach_norm)
]

index_data[, gimes_index_ma3 := frollmean(gimes_index, n = 3, align = "center")]
index_data[, gimes_yoy := (gimes_index / shift(gimes_index, 12) - 1) * 100]

7.2 GIMES Indeks kroz vrijeme

Prikaži kod
p_index <- ggplot(index_data, aes(x = yearmonth)) +
  geom_ribbon(aes(ymin = 0, ymax = gimes_index), fill = colors_gimes["accent"], alpha = 0.3) +
  geom_line(aes(y = gimes_index), color = colors_gimes["accent"], linewidth = 0.8, alpha = 0.5) +
  geom_line(aes(y = gimes_index_ma3), color = colors_gimes["primary"], linewidth = 1.2, na.rm = TRUE) +
  geom_point(aes(y = gimes_index_ma3), color = colors_gimes["primary"], size = 2, na.rm = TRUE) +
  scale_x_date(date_breaks = "3 months", date_labels = "%b\n%Y") +
  scale_y_continuous(limits = c(0, 100), breaks = seq(0, 100, 20)) +
  labs(
    title = "GIMES Indeks medijske inflacije",
    subtitle = "Kompozitni indeks medijske pozornosti na inflaciju (0-100) | Tamna linija = 3-mj. klizni prosjek",
    x = NULL,
    y = "GIMES Index"
  ) +
  theme(
    plot.title = element_text(face = "bold", size = 14),
    plot.subtitle = element_text(size = 10, color = "gray40"),
    panel.grid.minor = element_blank()
  )

p_index

GIMES Indeks medijske inflacije

7.3 Komponente indeksa

Prikaži kod
components_long <- melt(
  index_data[, .(yearmonth, volume_norm, length_norm, 
                 sentiment_inv = 100 - sentiment_norm, reach_norm)],
  id.vars = "yearmonth",
  variable.name = "component",
  value.name = "value"
)

component_labels <- c(
  "volume_norm" = "Volumen (40%)",
  "length_norm" = "Intenzitet (20%)",
  "sentiment_inv" = "Negativni sentiment (20%)",
  "reach_norm" = "Doseg (20%)"
)

components_long[, component_label := component_labels[as.character(component)]]

ggplot(components_long, aes(x = yearmonth, y = value, color = component_label)) +
  geom_line(linewidth = 1) +
  facet_wrap(~component_label, ncol = 2, scales = "free_y") +
  scale_x_date(date_breaks = "6 months", date_labels = "%b %y") +
  scale_color_manual(values = c(
    "Volumen (40%)" = colors_gimes["primary"],
    "Intenzitet (20%)" = colors_gimes["accent"],
    "Negativni sentiment (20%)" = colors_gimes["secondary"],
    "Doseg (20%)" = colors_gimes["success"]
  )) +
  labs(
    title = "Komponente GIMES indeksa",
    subtitle = "Normalizirane vrijednosti (0-100)",
    x = NULL,
    y = "Vrijednost",
    color = NULL
  ) +
  theme(
    plot.title = element_text(face = "bold"),
    legend.position = "none",
    axis.text.x = element_text(angle = 45, hjust = 1)
  )

Komponente GIMES indeksa

7.4 Tablica indeksa

Prikaži kod
index_table <- index_data[, .(
  Mjesec = format(yearmonth, "%b %Y"),
  `Broj članaka` = format(volume, big.mark = ","),
  `GIMES Index` = round(gimes_index, 1),
  `Klizni prosjek` = round(gimes_index_ma3, 1),
  `YoY promjena (%)` = ifelse(is.na(gimes_yoy), "-", paste0(ifelse(gimes_yoy > 0, "+", ""), round(gimes_yoy, 1)))
)]

kable(tail(index_table, 12), 
      caption = "GIMES Indeks - zadnjih 12 mjeseci",
      align = c("l", "r", "r", "r", "r")) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = FALSE) %>%
  row_spec(0, bold = TRUE, background = colors_gimes["primary"], color = "white")
GIMES Indeks - zadnjih 12 mjeseci
Mjesec Broj članaka GIMES Index Klizni prosjek YoY promjena (%)
vlj 2023 1,405 36.0 44.2 -36.3
ožu 2023 1,848 36.7 34.2 -44.5
tra 2023 959 30.0 25.7 -18.9
svi 2023 793 10.6 19.7 -74.3
lip 2023 904 18.4 20.2 -67.9
srp 2023 964 31.6 24.1 -30.6
kol 2023 1,184 22.4 29.7 -53.5
ruj 2023 1,451 35.3 27.4 -28.8
lis 2023 874 24.5 24.2 -49.9
stu 2023 728 12.8 21.9 -60.7
pro 2023 702 28.4 17.0 -24.9
sij 2024 246 9.7 NA -83.8

7.5 Export komponenti indeksa u Excel

Prikaži kod
# Pripremi podatke za export
export_data <- index_data[, .(
  Datum = yearmonth,
  Godina = year(yearmonth),
  Mjesec = month(yearmonth),
  Broj_clanaka = volume,
  Prosjecna_duljina = round(avg_length, 0),
  Prosjecni_sentiment = round(avg_sentiment, 3),
  Prosjecni_reach = round(avg_reach, 0),
  Semantic_ukupno = semantic_total,
  Semantic_inflacija = semantic_inflacija,
  Semantic_cijene = semantic_cijene,
  Semantic_troskovi = semantic_troskovi,
  Semantic_energija = semantic_energija,
  Semantic_hrana = semantic_hrana,
  Semantic_monetarna = semantic_monetarna,
  Semantic_place = semantic_place,
  Semantic_indeksi = semantic_indeksi,
  Volume_norm = round(volume_norm, 2),
  Length_norm = round(length_norm, 2),
  Sentiment_norm = round(sentiment_norm, 2),
  Sentiment_inv = round(100 - sentiment_norm, 2),
  Reach_norm = round(reach_norm, 2),
  Semantic_norm = round(semantic_norm, 2),
  GIMES_index = round(gimes_index, 2),
  GIMES_MA3 = round(gimes_index_ma3, 2),
  GIMES_YoY = round(gimes_yoy, 2)
)]

# Kreiraj workbook
wb <- createWorkbook()

# Dodaj glavni sheet
addWorksheet(wb, "Komponente_indeksa")
writeData(wb, "Komponente_indeksa", export_data)

# Stilovi
header_style <- createStyle(
  textDecoration = "bold",
  fgFill = "#2C3E50",
  fontColour = "white",
  halign = "center"
)
addStyle(wb, "Komponente_indeksa", header_style, rows = 1, cols = 1:ncol(export_data))

# Širina stupaca
setColWidths(wb, "Komponente_indeksa", cols = 1:ncol(export_data), widths = "auto")

# Dodaj sheet sa semantičkim kategorijama detaljno
addWorksheet(wb, "Semanticke_kategorije")
semantic_export <- monthly_semantic[, .(
  Datum = yearmonth,
  Broj_clanaka = N,
  Inflacija_direktno = count_inflacija_direktno,
  Cijene_poskupljenja = count_cijene_poskupljenja,
  Troskovi_zivota = count_troskovi_zivota,
  Energija_gorivo = count_energija_gorivo,
  Hrana = count_hrana,
  Monetarna_politika = count_monetarna_politika,
  Place_primanja = count_place_primanja,
  Indeksi_mjere = count_indeksi_mjere,
  Ukupno_semantic = count_all_semantic
)]
writeData(wb, "Semanticke_kategorije", semantic_export)
addStyle(wb, "Semanticke_kategorije", header_style, rows = 1, cols = 1:ncol(semantic_export))
setColWidths(wb, "Semanticke_kategorije", cols = 1:ncol(semantic_export), widths = "auto")

# Spremi workbook
output_path <- here("output", "gimes_komponente_indeksa.xlsx")
dir.create(here("output"), showWarnings = FALSE, recursive = TRUE)
saveWorkbook(wb, output_path, overwrite = TRUE)

message("Excel datoteka spremljena: ", output_path)

8 Dinamike različitih frekvencija

Ova sekcija proširuje Y/y perspektivu s alternativnim dinamikama uključujući M/m (mjesec na mjesec) sezonski prilagođene stope te 3M i 6M anualizirane stope.

8.1 Sezonska prilagodba

Prikaži kod
# Pripremi vremenski niz za sezonsku prilagodbu
# Koristimo STL dekompoziciju jer je robustnija za kratke serije s volatilnim podacima

# GIMES indeks kao ts objekt
gimes_ts <- ts(index_data$gimes_index, 
               start = c(year(min(index_data$yearmonth)), month(min(index_data$yearmonth))),
               frequency = 12)

# Semantički indeks kao ts objekt
semantic_ts <- ts(index_data$semantic_total,
                  start = c(year(min(index_data$yearmonth)), month(min(index_data$yearmonth))),
                  frequency = 12)

# Volumen kao ts objekt
volume_ts <- ts(index_data$volume,
                start = c(year(min(index_data$yearmonth)), month(min(index_data$yearmonth))),
                frequency = 12)

# STL dekompozicija za GIMES
stl_gimes <- tryCatch({
  stl(gimes_ts, s.window = "periodic", robust = TRUE)
}, error = function(e) {
  message("STL dekompozicija za GIMES nije uspjela: ", e$message)
  NULL
})

# STL dekompozicija za semantički indeks
stl_semantic <- tryCatch({
  stl(semantic_ts, s.window = "periodic", robust = TRUE)
}, error = function(e) {
  message("STL dekompozicija za semantički indeks nije uspjela: ", e$message)
  NULL
})

# STL dekompozicija za volumen
stl_volume <- tryCatch({
  stl(volume_ts, s.window = "periodic", robust = TRUE)
}, error = function(e) {
  message("STL dekompozicija za volumen nije uspjela: ", e$message)
  NULL
})

# Dodaj desezonirane vrijednosti u index_data
if(!is.null(stl_gimes)) {
  index_data[, gimes_sa := as.numeric(seasadj(stl_gimes))]
} else {
  index_data[, gimes_sa := gimes_index]  # Fallback na originalne vrijednosti
}

if(!is.null(stl_semantic)) {
  index_data[, semantic_sa := as.numeric(seasadj(stl_semantic))]
} else {
  index_data[, semantic_sa := semantic_total]
}

if(!is.null(stl_volume)) {
  index_data[, volume_sa := as.numeric(seasadj(stl_volume))]
} else {
  index_data[, volume_sa := volume]
}

8.2 Vizualizacija sezonske komponente

Prikaži kod
if(!is.null(stl_gimes)) {
  # Pripremi podatke za ggplot
  decomp_df <- data.table(
    yearmonth = index_data$yearmonth,
    Original = as.numeric(gimes_ts),
    Trend = as.numeric(stl_gimes$time.series[, "trend"]),
    Sezonska = as.numeric(stl_gimes$time.series[, "seasonal"]),
    Ostatak = as.numeric(stl_gimes$time.series[, "remainder"]),
    SA = as.numeric(seasadj(stl_gimes))
  )
  
  decomp_long <- melt(decomp_df, id.vars = "yearmonth", 
                      variable.name = "komponenta", value.name = "vrijednost")
  
  ggplot(decomp_long, aes(x = yearmonth, y = vrijednost)) +
    geom_line(color = colors_gimes["primary"], linewidth = 0.8) +
    facet_wrap(~komponenta, ncol = 1, scales = "free_y") +
    scale_x_date(date_breaks = "6 months", date_labels = "%b %Y") +
    labs(
      title = "STL dekompozicija GIMES indeksa",
      subtitle = "Original = Trend + Sezonska + Ostatak | SA = Sezonski prilagođeno (Trend + Ostatak)",
      x = NULL,
      y = "Vrijednost"
    ) +
    theme(
      plot.title = element_text(face = "bold"),
      strip.text = element_text(face = "bold")
    )
}

STL dekompozicija GIMES indeksa

8.3 Izračun različitih dinamika

Prikaži kod
# Funkcija za izračun anualiziranih stopa
annualize_rate <- function(rate, periods_per_year) {
  ((1 + rate/100)^periods_per_year - 1) * 100
}

# M/m stope (mjesec na mjesec) - sezonski prilagođeno
index_data[, `:=`(
  # M/m promjene (sezonski prilagođeno)
  gimes_mom_sa = (gimes_sa / shift(gimes_sa, 1) - 1) * 100,
  semantic_mom_sa = (semantic_sa / shift(semantic_sa, 1) - 1) * 100,
  volume_mom_sa = (volume_sa / shift(volume_sa, 1) - 1) * 100,
  
  # Y/y promjene (originalne)
  gimes_yoy_pct = (gimes_index / shift(gimes_index, 12) - 1) * 100,
  semantic_yoy_pct = (semantic_total / shift(semantic_total, 12) - 1) * 100,
  volume_yoy_pct = (volume / shift(volume, 12) - 1) * 100
)]

# 3M anualizirane stope (sezonski prilagođeno)
# Uzmi prosjek zadnja 3 mjeseca vs prethodna 3 mjeseca, anualiziraj
index_data[, `:=`(
  gimes_3m_avg = frollmean(gimes_sa, n = 3, align = "right"),
  semantic_3m_avg = frollmean(semantic_sa, n = 3, align = "right"),
  volume_3m_avg = frollmean(volume_sa, n = 3, align = "right")
)]

index_data[, `:=`(
  gimes_3m_prev = shift(gimes_3m_avg, 3),
  semantic_3m_prev = shift(semantic_3m_avg, 3),
  volume_3m_prev = shift(volume_3m_avg, 3)
)]

index_data[, `:=`(
  gimes_3m_ann = annualize_rate((gimes_3m_avg / gimes_3m_prev - 1) * 100, 4),
  semantic_3m_ann = annualize_rate((semantic_3m_avg / semantic_3m_prev - 1) * 100, 4),
  volume_3m_ann = annualize_rate((volume_3m_avg / volume_3m_prev - 1) * 100, 4)
)]

# 6M anualizirane stope (sezonski prilagođeno)
index_data[, `:=`(
  gimes_6m_avg = frollmean(gimes_sa, n = 6, align = "right"),
  semantic_6m_avg = frollmean(semantic_sa, n = 6, align = "right"),
  volume_6m_avg = frollmean(volume_sa, n = 6, align = "right")
)]

index_data[, `:=`(
  gimes_6m_prev = shift(gimes_6m_avg, 6),
  semantic_6m_prev = shift(semantic_6m_avg, 6),
  volume_6m_prev = shift(volume_6m_avg, 6)
)]

index_data[, `:=`(
  gimes_6m_ann = annualize_rate((gimes_6m_avg / gimes_6m_prev - 1) * 100, 2),
  semantic_6m_ann = annualize_rate((semantic_6m_avg / semantic_6m_prev - 1) * 100, 2),
  volume_6m_ann = annualize_rate((volume_6m_avg / volume_6m_prev - 1) * 100, 2)
)]

8.4 Usporedba različitih dinamika GIMES indeksa

Prikaži kod
dynamics_df <- index_data[, .(
  yearmonth,
  `Y/Y (%)` = gimes_yoy_pct,
  `M/M SA (%)` = gimes_mom_sa,
  `3M ann. SA (%)` = gimes_3m_ann,
  `6M ann. SA (%)` = gimes_6m_ann
)]

dynamics_long <- melt(dynamics_df, id.vars = "yearmonth",
                      variable.name = "dinamika", value.name = "stopa")

ggplot(dynamics_long[!is.na(stopa)], aes(x = yearmonth, y = stopa, color = dinamika)) +
  geom_hline(yintercept = 0, color = "gray50", linetype = "dashed") +
  geom_line(linewidth = 1) +
  facet_wrap(~dinamika, ncol = 2, scales = "free_y") +
  scale_x_date(date_breaks = "6 months", date_labels = "%b %y") +
  scale_color_manual(values = c(
    "Y/Y (%)" = colors_gimes["primary"],
    "M/M SA (%)" = colors_gimes["accent"],
    "3M ann. SA (%)" = colors_gimes["success"],
    "6M ann. SA (%)" = colors_gimes["warning"]
  )) +
  labs(
    title = "Usporedba različitih dinamika GIMES indeksa",
    subtitle = "Y/Y = godina na godinu | M/M SA = mjesec na mjesec sezonski prilagođeno | XM ann. SA = X-mjesečna anualizirana SA",
    x = NULL,
    y = "Promjena (%)",
    color = NULL
  ) +
  theme(
    plot.title = element_text(face = "bold"),
    legend.position = "none",
    strip.text = element_text(face = "bold"),
    axis.text.x = element_text(angle = 45, hjust = 1)
  )

Usporedba različitih dinamika GIMES indeksa

8.5 Sve dinamike na jednom grafu

Prikaži kod
ggplot(dynamics_long[!is.na(stopa) & dinamika != "M/M SA (%)"], 
       aes(x = yearmonth, y = stopa, color = dinamika)) +
  geom_hline(yintercept = 0, color = "gray50", linetype = "dashed") +
  geom_line(linewidth = 1, alpha = 0.8) +
  scale_x_date(date_breaks = "3 months", date_labels = "%b\n%Y") +
  scale_color_manual(values = c(
    "Y/Y (%)" = colors_gimes["primary"],
    "3M ann. SA (%)" = colors_gimes["success"],
    "6M ann. SA (%)" = colors_gimes["warning"]
  )) +
  labs(
    title = "Usporedba dinamika GIMES indeksa",
    subtitle = "Y/Y, 3M i 6M anualizirane sezonski prilagođene stope",
    x = NULL,
    y = "Promjena (%)",
    color = "Dinamika"
  ) +
  theme(
    plot.title = element_text(face = "bold"),
    legend.position = "bottom"
  )

Sve dinamike GIMES indeksa na jednom grafu

8.6 Dinamike semantičkog indeksa

Prikaži kod
semantic_dynamics_df <- index_data[, .(
  yearmonth,
  `Y/Y (%)` = semantic_yoy_pct,
  `3M ann. SA (%)` = semantic_3m_ann,
  `6M ann. SA (%)` = semantic_6m_ann
)]

semantic_dynamics_long <- melt(semantic_dynamics_df, id.vars = "yearmonth",
                               variable.name = "dinamika", value.name = "stopa")

ggplot(semantic_dynamics_long[!is.na(stopa)], 
       aes(x = yearmonth, y = stopa, color = dinamika)) +
  geom_hline(yintercept = 0, color = "gray50", linetype = "dashed") +
  geom_line(linewidth = 1, alpha = 0.8) +
  scale_x_date(date_breaks = "3 months", date_labels = "%b\n%Y") +
  scale_color_manual(values = c(
    "Y/Y (%)" = colors_gimes["secondary"],
    "3M ann. SA (%)" = colors_gimes["accent"],
    "6M ann. SA (%)" = colors_gimes["purple"]
  )) +
  labs(
    title = "Dinamike ukupnog semantičkog indeksa",
    subtitle = "Y/Y, 3M i 6M anualizirane sezonski prilagođene stope",
    x = NULL,
    y = "Promjena (%)",
    color = "Dinamika"
  ) +
  theme(
    plot.title = element_text(face = "bold"),
    legend.position = "bottom"
  )

Dinamike semantičkog indeksa

8.7 Tablica dinamika

Prikaži kod
dynamics_table <- index_data[, .(
  Mjesec = format(yearmonth, "%b %Y"),
  GIMES = round(gimes_index, 1),
  `GIMES SA` = round(gimes_sa, 1),
  `Y/Y (%)` = round(gimes_yoy_pct, 1),
  `M/M SA (%)` = round(gimes_mom_sa, 1),
  `3M ann. (%)` = round(gimes_3m_ann, 1),
  `6M ann. (%)` = round(gimes_6m_ann, 1)
)]

kable(tail(dynamics_table, 12), 
      caption = "Dinamike GIMES indeksa - zadnjih 12 mjeseci",
      align = c("l", rep("r", 6))) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = FALSE) %>%
  row_spec(0, bold = TRUE, background = colors_gimes["primary"], color = "white")
Dinamike GIMES indeksa - zadnjih 12 mjeseci
Mjesec GIMES GIMES SA Y/Y (%) M/M SA (%) 3M ann. (%) 6M ann. (%)
vlj 2023 36.0 39.4 -36.3 -21.1 22.2 -33.1
ožu 2023 36.7 36.8 -44.5 -6.8 13.2 -22.3
tra 2023 30.0 32.2 -18.9 -12.4 -51.7 -30.0
svi 2023 10.6 6.3 -74.3 -80.4 -88.4 -49.8
lip 2023 18.4 29.7 -67.9 370.7 -91.4 -43.8
srp 2023 31.6 29.3 -30.6 -1.7 -86.8 -57.5
kol 2023 22.4 28.1 -53.5 -4.0 79.1 -58.5
ruj 2023 35.3 25.8 -28.8 -8.1 120.2 -62.9
lis 2023 24.5 17.9 -49.9 -30.5 46.4 -66.9
stu 2023 12.8 20.6 -60.7 14.8 -70.2 -45.1
pro 2023 28.4 30.2 -24.9 46.8 -53.2 -39.0
sij 2024 9.7 -0.1 -83.8 -100.4 -75.2 -50.2

8.8 Export dinamika u Excel

Prikaži kod
# Dodaj sheet s dinamikama u postojeći workbook ili kreiraj novi
dynamics_export <- index_data[, .(
  Datum = yearmonth,
  GIMES_original = round(gimes_index, 2),
  GIMES_SA = round(gimes_sa, 2),
  GIMES_YoY = round(gimes_yoy_pct, 2),
  GIMES_MoM_SA = round(gimes_mom_sa, 2),
  GIMES_3M_ann = round(gimes_3m_ann, 2),
  GIMES_6M_ann = round(gimes_6m_ann, 2),
  Semantic_original = semantic_total,
  Semantic_SA = round(semantic_sa, 0),
  Semantic_YoY = round(semantic_yoy_pct, 2),
  Semantic_3M_ann = round(semantic_3m_ann, 2),
  Semantic_6M_ann = round(semantic_6m_ann, 2),
  Volume_original = volume,
  Volume_SA = round(volume_sa, 0),
  Volume_YoY = round(volume_yoy_pct, 2),
  Volume_3M_ann = round(volume_3m_ann, 2),
  Volume_6M_ann = round(volume_6m_ann, 2)
)]

# Dodaj u workbook
addWorksheet(wb, "Dinamike")
writeData(wb, "Dinamike", dynamics_export)
addStyle(wb, "Dinamike", header_style, rows = 1, cols = 1:ncol(dynamics_export))
setColWidths(wb, "Dinamike", cols = 1:ncol(dynamics_export), widths = "auto")

# Dodaj sheet sa sezonskom komponentom ako postoji
if(!is.null(stl_gimes)) {
  seasonal_export <- data.table(
    Datum = index_data$yearmonth,
    GIMES_trend = round(as.numeric(stl_gimes$time.series[, "trend"]), 2),
    GIMES_sezonska = round(as.numeric(stl_gimes$time.series[, "seasonal"]), 2),
    GIMES_ostatak = round(as.numeric(stl_gimes$time.series[, "remainder"]), 2)
  )
  
  if(!is.null(stl_semantic)) {
    seasonal_export[, `:=`(
      Semantic_trend = round(as.numeric(stl_semantic$time.series[, "trend"]), 0),
      Semantic_sezonska = round(as.numeric(stl_semantic$time.series[, "seasonal"]), 0),
      Semantic_ostatak = round(as.numeric(stl_semantic$time.series[, "remainder"]), 0)
    )]
  }
  
  if(!is.null(stl_volume)) {
    seasonal_export[, `:=`(
      Volume_trend = round(as.numeric(stl_volume$time.series[, "trend"]), 0),
      Volume_sezonska = round(as.numeric(stl_volume$time.series[, "seasonal"]), 0),
      Volume_ostatak = round(as.numeric(stl_volume$time.series[, "remainder"]), 0)
    )]
  }
  
  addWorksheet(wb, "Sezonska_dekompozicija")
  writeData(wb, "Sezonska_dekompozicija", seasonal_export)
  addStyle(wb, "Sezonska_dekompozicija", header_style, rows = 1, cols = 1:ncol(seasonal_export))
  setColWidths(wb, "Sezonska_dekompozicija", cols = 1:ncol(seasonal_export), widths = "auto")
}

# Spremi ažurirani workbook
saveWorkbook(wb, output_path, overwrite = TRUE)
message("Excel datoteka ažurirana s dinamikama: ", output_path)

9 Validacija sa službenim podacima

9.1 Dohvaćanje službenih podataka

Prikaži kod
message("Dohvaćanje HICP podataka iz Eurostata...")

eurostat_headline <- NULL
eurostat_core <- NULL

tryCatch({
  hicp_data <- get_eurostat("prc_hicp_manr", 
                            filters = list(geo = "HR", 
                                          coicop = "CP00",
                                          unit = "RCH_A"),
                            time_format = "date")
  
  setDT(hicp_data)
  eurostat_headline <<- hicp_data[time >= "2021-01-01" & time <= "2024-11-01", 
                                   .(yearmonth = time, eurostat_hicp = values)]
  
  core_data <- get_eurostat("prc_hicp_manr",
                           filters = list(geo = "HR",
                                         coicop = "CP00XEF",
                                         unit = "RCH_A"),
                           time_format = "date")
  
  setDT(core_data)
  eurostat_core <<- core_data[time >= "2021-01-01" & time <= "2024-11-01",
                              .(yearmonth = time, eurostat_core = values)]
  
  message("Uspješno dohvaćeno ", nrow(eurostat_headline), " mjeseci Eurostat podataka")
  
}, error = function(e) {
  message("UPOZORENJE: Ne mogu se spojiti na Eurostat. Koristim backup podatke.")
  message("Greška: ", e$message)
  
  eurostat_headline <<- data.table(
    yearmonth = seq(as.Date("2021-01-01"), as.Date("2024-11-01"), by = "month"),
    eurostat_hicp = c(
      0.2, 0.6, 0.8, 1.9, 2.4, 2.3, 2.6, 3.0, 3.3, 3.8, 4.8, 5.5,
      5.8, 6.3, 7.3, 9.4, 10.8, 12.1, 12.3, 12.4, 12.8, 13.0, 13.0, 12.7,
      12.0, 11.1, 10.5, 9.2, 8.4, 8.2, 7.3, 7.7, 7.1, 5.3, 4.9, 4.7,
      4.3, 4.0, 3.9, 3.7, 3.6, 3.4, 3.2, 2.9, 2.8, 2.6, 2.4
    )
  )
  
  eurostat_core <<- data.table(
    yearmonth = seq(as.Date("2021-01-01"), as.Date("2024-11-01"), by = "month"),
    eurostat_core = c(
      0.5, 0.8, 1.0, 1.5, 1.8, 1.9, 2.0, 2.2, 2.4, 2.7, 3.2, 3.8,
      4.2, 4.8, 5.6, 6.8, 7.9, 8.7, 8.9, 9.1, 9.4, 9.8, 10.2, 10.5,
      10.8, 10.5, 10.0, 9.2, 8.5, 8.0, 7.2, 7.4, 7.0, 6.2, 5.8, 5.5,
      5.2, 4.9, 4.6, 4.3, 4.1, 3.8, 3.5, 3.3, 3.2, 3.0, 2.9
    )
  )
})

dzs_inflation <- data.table(
  yearmonth = seq(as.Date("2021-01-01"), as.Date("2024-11-01"), by = "month"),
  dzs_cpi = c(
    0.1, 0.5, 0.7, 1.8, 2.3, 2.2, 2.5, 2.9, 3.2, 3.7, 4.7, 5.4,
    5.7, 6.2, 7.2, 9.3, 10.7, 12.0, 12.2, 12.3, 12.7, 12.9, 12.9, 12.6,
    11.9, 11.0, 10.4, 9.1, 8.3, 8.1, 7.2, 7.6, 7.0, 5.2, 4.8, 4.6,
    4.2, 3.9, 3.8, 3.6, 3.5, 3.3, 3.1, 2.8, 2.7, 2.5, 2.3
  )
)

comparison <- merge(index_data, eurostat_headline, by = "yearmonth", all.x = TRUE)
comparison <- merge(comparison, eurostat_core, by = "yearmonth", all.x = TRUE)
comparison <- merge(comparison, dzs_inflation, by = "yearmonth", all.x = TRUE)

9.2 GIMES vs DZS CPI

Prikaži kod
coef_dzs <- 100 / max(comparison$dzs_cpi, na.rm = TRUE)

ggplot(comparison, aes(x = yearmonth)) +
  geom_line(aes(y = gimes_index, color = "GIMES Index"), linewidth = 1.2) +
  geom_point(aes(y = gimes_index), color = colors_gimes["primary"], size = 2, alpha = 0.6) +
  geom_line(aes(y = dzs_cpi * coef_dzs, color = "DZS CPI"), 
            linewidth = 1.2, linetype = "solid") +
  geom_point(aes(y = dzs_cpi * coef_dzs), color = colors_gimes["warning"], 
             size = 2, alpha = 0.6) +
  scale_y_continuous(
    name = "GIMES Index (0-100)",
    sec.axis = sec_axis(~./coef_dzs, name = "DZS CPI (YoY %)", 
                       labels = function(x) paste0(x, "%"))
  ) +
  scale_x_date(date_breaks = "3 months", date_labels = "%b\n%Y") +
  scale_color_manual(values = c("GIMES Index" = colors_gimes["primary"], 
                                "DZS CPI" = colors_gimes["warning"])) +
  labs(
    title = "GIMES indeks medijske inflacije vs DZS CPI",
    subtitle = "Usporedba medijske percepcije i službene inflacije (DZS nacionalna metodologija)",
    x = NULL,
    color = NULL
  ) +
  theme(
    plot.title = element_text(face = "bold", size = 13),
    plot.subtitle = element_text(size = 10),
    legend.position = "bottom",
    axis.title.y.right = element_text(color = colors_gimes["warning"], face = "bold"),
    axis.text.y.right = element_text(color = colors_gimes["warning"]),
    axis.title.y.left = element_text(color = colors_gimes["primary"], face = "bold")
  )

GIMES indeks vs DZS CPI inflacija

9.3 Dnevni broj članaka kao samostalni indikator vs službena inflacija

Prikaži kod
# Pripremi dnevne podatke sa inflacijom
daily_with_inflation <- merge(daily, 
                              comparison[, .(yearmonth, eurostat_hicp)], 
                              by.x = "date", 
                              by.y = "yearmonth", 
                              all.x = TRUE)

# Interpoliraj inflaciju za svaki dan
daily_with_inflation[, eurostat_hicp := zoo::na.locf(eurostat_hicp, na.rm = FALSE)]

coef_daily <- max(daily$MA30, na.rm = TRUE) / max(comparison$eurostat_hicp, na.rm = TRUE)

ggplot(daily_with_inflation[!is.na(eurostat_hicp)], aes(x = date)) +
  geom_line(aes(y = MA30, color = "30-dnevni prosjek članaka"), linewidth = 1.2, na.rm = TRUE) +
  geom_line(aes(y = eurostat_hicp * coef_daily, color = "Eurostat HICP"), 
            linewidth = 1.2, linetype = "dashed") +
  scale_y_continuous(
    name = "Broj članaka (30-dnevni MA)",
    sec.axis = sec_axis(~./coef_daily, name = "HICP Inflacija (YoY %)",
                       labels = function(x) paste0(x, "%"))
  ) +
  scale_x_date(date_breaks = "3 months", date_labels = "%b\n%Y") +
  scale_color_manual(values = c("30-dnevni prosjek članaka" = colors_gimes["accent"],
                                "Eurostat HICP" = colors_gimes["secondary"])) +
  labs(
    title = "Dnevna frekvencija članaka o inflaciji kao samostalni indikator",
    subtitle = "Usporedba dnevne medijske pozornosti (30-dnevni klizni prosjek) i službene inflacije",
    x = NULL,
    color = NULL
  ) +
  theme(
    plot.title = element_text(face = "bold", size = 13),
    plot.subtitle = element_text(size = 10),
    legend.position = "bottom",
    axis.title.y.right = element_text(color = colors_gimes["secondary"], face = "bold"),
    axis.text.y.right = element_text(color = colors_gimes["secondary"]),
    axis.title.y.left = element_text(color = colors_gimes["accent"], face = "bold")
  )

Dnevni broj članaka o inflaciji vs službena inflacija

9.4 Broj spominjanja riječi inflacija vs službena inflacija

Prikaži kod
# Koristimo već izračunate podatke iz semantic analize
monthly_mentions <- monthly_semantic[, .(
  yearmonth,
  total_mentions = count_inflacija_direktno,
  article_count = N
)]

# Spoji s Eurostat podacima
monthly_mentions <- merge(monthly_mentions, eurostat_headline, by = "yearmonth", all.x = TRUE)

# Koeficijent za dual axis
coef_mentions <- max(monthly_mentions$total_mentions, na.rm = TRUE) / 
                 max(monthly_mentions$eurostat_hicp, na.rm = TRUE)

ggplot(monthly_mentions, aes(x = yearmonth)) +
  geom_col(aes(y = total_mentions), fill = colors_gimes["primary"], alpha = 0.7, width = 25) +
  geom_line(aes(y = eurostat_hicp * coef_mentions, color = "Eurostat HICP"), 
            linewidth = 1.5) +
  geom_point(aes(y = eurostat_hicp * coef_mentions), 
             color = colors_gimes["secondary"], size = 2.5) +
  scale_y_continuous(
    name = "Broj spominjanja riječi inflacija",
    labels = comma,
    sec.axis = sec_axis(~./coef_mentions, name = "HICP Inflacija (YoY %)",
                       labels = function(x) paste0(x, "%"))
  ) +
  scale_x_date(date_breaks = "3 months", date_labels = "%b\n%Y") +
  scale_color_manual(values = c("Eurostat HICP" = colors_gimes["secondary"])) +
  labs(
    title = "Broj spominjanja riječi inflacija vs službena inflacija",
    subtitle = "Ukupan mjesečni broj pojavljivanja korijena riječi inflacij* u medijskim člancima | Izvor inflacije: Eurostat HICP",
    x = NULL,
    color = NULL
  ) +
  theme(
    plot.title = element_text(face = "bold", size = 14),
    plot.subtitle = element_text(size = 10, color = "gray40"),
    legend.position = "bottom",
    axis.title.y.right = element_text(color = colors_gimes["secondary"], face = "bold"),
    axis.text.y.right = element_text(color = colors_gimes["secondary"]),
    axis.title.y.left = element_text(color = colors_gimes["primary"], face = "bold"),
    panel.grid.minor = element_blank()
  )

Mjesečni broj spominjanja riječi inflacija vs Eurostat HICP

9.5 Statistike spominjanja riječi inflacija

Prikaži kod
word_stats <- data.table(
  Metrika = c(
    "Ukupan broj spominjanja riječi inflacija",
    "Prosječno spominjanja po članku",
    "Mjesec s najviše spominjanja",
    "Maksimalan broj spominjanja (mjesec)",
    "Korelacija s Eurostat HICP"
  ),
  Vrijednost = c(
    format(sum(monthly_mentions$total_mentions, na.rm = TRUE), big.mark = ","),
    round(mean(dt$count_inflacija_direktno, na.rm = TRUE), 2),
    format(monthly_mentions[which.max(total_mentions), yearmonth], "%B %Y"),
    format(max(monthly_mentions$total_mentions, na.rm = TRUE), big.mark = ","),
    round(cor(monthly_mentions$total_mentions, monthly_mentions$eurostat_hicp, use = "complete.obs"), 3)
  )
)

kable(word_stats, caption = "Statistike spominjanja riječi inflacija") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Statistike spominjanja riječi inflacija
Metrika Vrijednost
Ukupan broj spominjanja riječi inflacija 27,149
Prosječno spominjanja po članku 0.59
Mjesec s najviše spominjanja lipanj 2022
Maksimalan broj spominjanja (mjesec) 1,556
Korelacija s Eurostat HICP 0.867

9.6 Korelacijska tablica

Prikaži kod
correlations <- data.table(
  Usporedba = c(
    "GIMES Index vs Eurostat HICP",
    "GIMES Index vs Eurostat Core",
    "GIMES Index vs DZS CPI",
    "Volumen (broj članaka) vs Eurostat HICP",
    "Semantički indeks (ukupno) vs Eurostat HICP",
    "Semantički (inflacija direktno) vs Eurostat HICP"
  ),
  Korelacija = c(
    round(cor(comparison$gimes_index, comparison$eurostat_hicp, use = "complete.obs"), 3),
    round(cor(comparison$gimes_index, comparison$eurostat_core, use = "complete.obs"), 3),
    round(cor(comparison$gimes_index, comparison$dzs_cpi, use = "complete.obs"), 3),
    round(cor(comparison$volume, comparison$eurostat_hicp, use = "complete.obs"), 3),
    round(cor(comparison$semantic_total, comparison$eurostat_hicp, use = "complete.obs"), 3),
    round(cor(comparison$semantic_inflacija, comparison$eurostat_hicp, use = "complete.obs"), 3)
  )
)

kable(correlations, caption = "Korelacije između različitih mjera inflacije") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
  row_spec(which.max(correlations$Korelacija), bold = TRUE, background = colors_gimes["success"])
Korelacije između različitih mjera inflacije
Usporedba Korelacija
GIMES Index vs Eurostat HICP 0.392
GIMES Index vs Eurostat Core 0.210
GIMES Index vs DZS CPI 0.392
Volumen (broj članaka) vs Eurostat HICP 0.732
Semantički indeks (ukupno) vs Eurostat HICP 0.675
Semantički (inflacija direktno) vs Eurostat HICP 0.867

10 Analiza prediktivnosti

10.1 Cross-correlation analiza

Prikaži kod
comparison_complete <- comparison[!is.na(gimes_index) & !is.na(eurostat_hicp)]

if(nrow(comparison_complete) >= 24) {
  ccf_result <- ccf(
    comparison_complete$gimes_index,
    comparison_complete$eurostat_hicp,
    lag.max = 12,
    plot = FALSE,
    na.action = na.pass
  )
  
  ccf_df <- data.table(
    lag = ccf_result$lag[,,1],
    correlation = ccf_result$acf[,,1]
  )
  
  max_corr <- ccf_df[which.max(abs(correlation))]
  
  ggplot(ccf_df, aes(x = lag, y = correlation)) +
    geom_hline(yintercept = 0, color = "gray50") +
    geom_hline(yintercept = c(-0.2, 0.2), linetype = "dashed", color = "gray70") +
    geom_segment(aes(xend = lag, yend = 0), linewidth = 1.5, color = colors_gimes["accent"]) +
    geom_point(size = 3, color = colors_gimes["primary"]) +
    geom_vline(xintercept = max_corr$lag, color = colors_gimes["secondary"], 
               linetype = "dashed", linewidth = 1) +
    annotate("text", x = max_corr$lag, y = max_corr$correlation + 0.1,
             label = paste0("Max: pomak=", max_corr$lag, 
                          "\nr=", round(max_corr$correlation, 3)),
             color = colors_gimes["secondary"], fontface = "bold") +
    scale_x_continuous(breaks = seq(-12, 12, 2)) +
    labs(
      title = "Unakrsna korelacija: GIMES indeks i HICP inflacija",
      subtitle = "Negativni pomak = GIMES predvodi inflaciju | Pozitivni pomak = GIMES prati inflaciju",
      x = "Pomak (mjeseci)",
      y = "Korelacija"
    ) +
    theme(plot.title = element_text(face = "bold"))
}

Unakrsna korelacija: GIMES vs HICP

10.2 Korelacije s pomacima

Prikaži kod
lags <- -6:6
correlations_lag <- sapply(lags, function(lag) {
  if(lag < 0) {
    x <- comparison$gimes_index[1:(nrow(comparison) + lag)]
    y <- comparison$eurostat_hicp[(abs(lag) + 1):nrow(comparison)]
  } else if(lag > 0) {
    x <- comparison$gimes_index[(lag + 1):nrow(comparison)]
    y <- comparison$eurostat_hicp[1:(nrow(comparison) - lag)]
  } else {
    x <- comparison$gimes_index
    y <- comparison$eurostat_hicp
  }
  cor(x, y, use = "complete.obs")
})

lag_table <- data.table(
  Pomak = lags,
  Opis = c(
    "GIMES -6 mjeseci",
    "GIMES -5 mjeseci",
    "GIMES -4 mjeseci",
    "GIMES -3 mjeseci",
    "GIMES -2 mjeseci",
    "GIMES -1 mjesec",
    "Istovremeno",
    "HICP -1 mjesec",
    "HICP -2 mjeseca",
    "HICP -3 mjeseca",
    "HICP -4 mjeseca",
    "HICP -5 mjeseci",
    "HICP -6 mjeseci"
  ),
  Korelacija = round(correlations_lag, 3)
)[order(-Korelacija)]

kable(lag_table, 
      caption = "Korelacije GIMES indeksa i HICP inflacije sa različitim vremenskim pomacima",
      align = c("c", "l", "r")) %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
  row_spec(which.max(lag_table$Korelacija), bold = TRUE, background = colors_gimes["success"])
Korelacije GIMES indeksa i HICP inflacije sa različitim vremenskim pomacima
Pomak Opis Korelacija
-5 GIMES -5 mjeseci 0.651
-6 GIMES -6 mjeseci 0.620
-4 GIMES -4 mjeseci 0.619
-3 GIMES -3 mjeseci 0.590
-2 GIMES -2 mjeseci 0.540
-1 GIMES -1 mjesec 0.459
0 Istovremeno 0.392
1 HICP -1 mjesec 0.342
2 HICP -2 mjeseca 0.204
3 HICP -3 mjeseca 0.089
4 HICP -4 mjeseca -0.047
5 HICP -5 mjeseci -0.138
6 HICP -6 mjeseci -0.260

10.3 Cross-correlation semantičkog indeksa

Prikaži kod
if(nrow(comparison_complete) >= 24) {
  ccf_semantic <- ccf(
    comparison_complete$semantic_total,
    comparison_complete$eurostat_hicp,
    lag.max = 12,
    plot = FALSE,
    na.action = na.pass
  )
  
  ccf_semantic_df <- data.table(
    lag = ccf_semantic$lag[,,1],
    correlation = ccf_semantic$acf[,,1]
  )
  
  max_corr_semantic <- ccf_semantic_df[which.max(abs(correlation))]
  
  ggplot(ccf_semantic_df, aes(x = lag, y = correlation)) +
    geom_hline(yintercept = 0, color = "gray50") +
    geom_hline(yintercept = c(-0.2, 0.2), linetype = "dashed", color = "gray70") +
    geom_segment(aes(xend = lag, yend = 0), linewidth = 1.5, color = colors_gimes["success"]) +
    geom_point(size = 3, color = colors_gimes["primary"]) +
    geom_vline(xintercept = max_corr_semantic$lag, color = colors_gimes["secondary"], 
               linetype = "dashed", linewidth = 1) +
    annotate("text", x = max_corr_semantic$lag, y = max_corr_semantic$correlation + 0.1,
             label = paste0("Max: pomak=", max_corr_semantic$lag, 
                          "\nr=", round(max_corr_semantic$correlation, 3)),
             color = colors_gimes["secondary"], fontface = "bold") +
    scale_x_continuous(breaks = seq(-12, 12, 2)) +
    labs(
      title = "Unakrsna korelacija: Semantički indeks i HICP inflacija",
      subtitle = "Negativni pomak = Semantički indeks predvodi inflaciju | Pozitivni pomak = prati inflaciju",
      x = "Pomak (mjeseci)",
      y = "Korelacija"
    ) +
    theme(plot.title = element_text(face = "bold"))
}

Unakrsna korelacija: Semantički indeks vs HICP

11 Zaključci i implikacije

11.1 Ključni nalazi

Prikaži kod
peak_month <- index_data[which.max(gimes_index), yearmonth]
peak_value <- index_data[which.max(gimes_index), gimes_index]

peak_inflation_month <- comparison[which.max(eurostat_hicp), yearmonth]
peak_inflation_value <- comparison[which.max(eurostat_hicp), eurostat_hicp]

# Nađi najbolju korelaciju među semantičkim kategorijama
best_semantic <- correlation_results[Kategorija != "SVE KATEGORIJE"][which.max(Korelacija)]

findings <- data.table(
  Nalaz = c(
    "Ukupno analiziranih članaka",
    "Vremenski raspon analize",
    "Broj izvora",
    "",
    "Vrh GIMES indeksa",
    "Vrijednost vrha",
    "",
    "Vrh inflacije (HICP)",
    "Vrijednost vrha",
    "",
    "Korelacija GIMES-HICP",
    "Korelacija Semantički-HICP",
    "Najbolja semantička kategorija",
    "Optimalni pomak",
    "",
    "Prosječna duljina članka",
    "Dominantan sentiment"
  ),
  Vrijednost = c(
    format(nrow(dt), big.mark = ","),
    paste(format(min(dt$date), "%m/%Y"), "-", format(max(dt$date), "%m/%Y")),
    as.character(length(unique(dt$FROM))),
    "",
    format(peak_month, "%B %Y"),
    round(peak_value, 1),
    "",
    format(peak_inflation_month, "%B %Y"),
    paste0(round(peak_inflation_value, 1), "%"),
    "",
    round(cor(comparison$gimes_index, comparison$eurostat_hicp, use = "complete.obs"), 3),
    round(cor(comparison$semantic_total, comparison$eurostat_hicp, use = "complete.obs"), 3),
    paste0(best_semantic$Kategorija, " (r=", best_semantic$Korelacija, ")"),
    paste0(lags[which.max(abs(correlations_lag))], " mjeseci"),
    "",
    paste0(format(round(median(dt$text_length)), big.mark = ","), " znakova"),
    ifelse(sum(dt$AUTO_SENTIMENT == -1, na.rm = TRUE) > sum(dt$AUTO_SENTIMENT == 1, na.rm = TRUE),
           "Negativan", "Pozitivan/Neutralan")
  )
)

kable(findings, caption = "Sažetak ključnih nalaza analize") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
  row_spec(c(4, 7, 10, 15), background = colors_gimes["light"])
Sažetak ključnih nalaza analize
Nalaz Vrijednost
Ukupno analiziranih članaka 46,107
Vremenski raspon analize 01/2021 - 01/2024
Broj izvora 115
Vrh GIMES indeksa ožujak 2022
Vrijednost vrha 66.1
Vrh inflacije (HICP) listopad 2022
Vrijednost vrha 13%
Korelacija GIMES-HICP 0.392
Korelacija Semantički-HICP 0.675
Najbolja semantička kategorija inflacija_direktno (r=0.868)
Optimalni pomak -5 mjeseci
Prosječna duljina članka 2,725 znakova
Dominantan sentiment Negativan

11.2 Finalni export u Excel

Prikaži kod
# Dodaj sheet sa svim korelacijama
all_correlations <- rbind(
  correlation_results[, .(Tip = "Semantička kategorija", Naziv = Kategorija, Korelacija, P_vrijednost)],
  data.table(
    Tip = "Indeks",
    Naziv = c("GIMES vs HICP", "GIMES vs Core", "GIMES vs DZS CPI", "Volumen vs HICP"),
    Korelacija = correlations$Korelacija,
    P_vrijednost = NA_real_
  )
)

addWorksheet(wb, "Korelacije")
writeData(wb, "Korelacije", all_correlations)
addStyle(wb, "Korelacije", header_style, rows = 1, cols = 1:ncol(all_correlations))
setColWidths(wb, "Korelacije", cols = 1:ncol(all_correlations), widths = "auto")

# Spremi finalni workbook
saveWorkbook(wb, output_path, overwrite = TRUE)
message("Finalna Excel datoteka spremljena: ", output_path)

Izvještaj generiran: 2025-12-29 12:26:19.889367

GIMES Istraživački projekt analize medijskog sadržaja